 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.actions;

 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
 import org.eclipse.ui.internal.ide.actions.BuildUtilities;

 /**
  * Standard action for full and incremental builds of all projects within the
  * workspace.
  * <p>
  * This class may be instantiated; it is not intended to be subclassed.
  * </p>
  */
 public class GlobalBuildAction extends Action implements
         ActionFactory.IWorkbenchAction {
     /**
      * The type of build performed by this action. Can be either
      * <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
      * <code>IncrementalProjectBuilder.FULL_BUILD</code>.
      */
     private int buildType;

     /**
      * The workbench window; or <code>null</code> if this action has been
      * <code>dispose</code>d.
      */
     private IWorkbenchWindow workbenchWindow;

     /**
      * Creates a new action of the appropriate type. The action id is
      * <code>IWorkbenchActionConstants.BUILD</code> for incremental builds and
      * <code>IWorkbenchActionConstants.REBUILD_ALL</code> for full builds.
      *
      * @param workbench
      * the active workbench
      * @param shell
      * the shell for any dialogs
      * @param type
      * the type of build; one of
      * <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
      * <code>IncrementalProjectBuilder.FULL_BUILD</code>
      *
      * @deprecated use GlobalBuildAction(IWorkbenchWindow, type) instead
      */
     public GlobalBuildAction(IWorkbench workbench, Shell shell, int type) {
         // always use active window; ignore shell
 this(workbench.getActiveWorkbenchWindow(), type);
         if (shell == null) {
             throw new IllegalArgumentException ();
         }
     }

     /**
      * Creates a new action of the appropriate type. The action id is
      * <code>IWorkbenchActionConstants.BUILD</code> for incremental builds and
      * <code>IWorkbenchActionConstants.REBUILD_ALL</code> for full builds.
      *
      * @param window
      * the window in which this action appears
      * @param type
      * the type of build; one of
      * <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
      * <code>IncrementalProjectBuilder.FULL_BUILD</code>
      */
     public GlobalBuildAction(IWorkbenchWindow window, int type) {
         if (window == null) {
             throw new IllegalArgumentException ();
         }
         this.workbenchWindow = window;
         setBuildType(type);
     }

     /**
      * Sets the build type.
      *
      * @param type
      * the type of build; one of
      * <code>IncrementalProjectBuilder.INCREMENTAL_BUILD</code> or
      * <code>IncrementalProjectBuilder.FULL_BUILD</code>
      */
     private void setBuildType(int type) {
         // allow AUTO_BUILD as well for backwards compatibility, but treat it
 // the same as INCREMENTAL_BUILD
 switch (type) {
         case IncrementalProjectBuilder.INCREMENTAL_BUILD:
         case IncrementalProjectBuilder.AUTO_BUILD:
             setText(IDEWorkbenchMessages.GlobalBuildAction_text);
             setToolTipText(IDEWorkbenchMessages.GlobalBuildAction_toolTip);
             setId("build"); //$NON-NLS-1$
 workbenchWindow.getWorkbench().getHelpSystem().setHelp(this,
                     IIDEHelpContextIds.GLOBAL_INCREMENTAL_BUILD_ACTION);
             setImageDescriptor(IDEInternalWorkbenchImages
                     .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC));
             setDisabledImageDescriptor(IDEInternalWorkbenchImages
                     .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED));
             setActionDefinitionId("org.eclipse.ui.project.buildAll"); //$NON-NLS-1$
 break;
         case IncrementalProjectBuilder.FULL_BUILD:
             setText(IDEWorkbenchMessages.GlobalBuildAction_rebuildText);
             setToolTipText(IDEWorkbenchMessages.GlobalBuildAction_rebuildToolTip);
             setId("rebuildAll"); //$NON-NLS-1$
 workbenchWindow.getWorkbench().getHelpSystem().setHelp(this,
                     IIDEHelpContextIds.GLOBAL_FULL_BUILD_ACTION);
             setActionDefinitionId("org.eclipse.ui.project.rebuildAll"); //$NON-NLS-1$
 break;
         default:
             throw new IllegalArgumentException ("Invalid build type"); //$NON-NLS-1$
 }
         this.buildType = type;
     }

     /**
      * Returns the shell to use.
      */
     private Shell getShell() {
         return workbenchWindow.getShell();
     }

     /**
      * Returns the operation name to use
      */
     private String getOperationMessage() {
         if (buildType == IncrementalProjectBuilder.INCREMENTAL_BUILD) {
             return IDEWorkbenchMessages.GlobalBuildAction_buildOperationTitle;
         }
         return IDEWorkbenchMessages.GlobalBuildAction_rebuildAllOperationTitle;
     }

     /**
      * Builds all projects within the workspace. Does not save any open editors.
      */
     public void doBuild() {
         doBuildOperation();
     }

     /**
      * Invokes a build on all projects within the workspace. Reports any errors
      * with the build to the user.
      */
     /* package */void doBuildOperation() {
         Job buildJob = new Job(IDEWorkbenchMessages.GlobalBuildAction_jobTitle) {
             /*
              * (non-Javadoc)
              *
              * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
              */
             protected IStatus run(IProgressMonitor monitor) {
                 final MultiStatus status = new MultiStatus(
                         PlatformUI.PLUGIN_ID, 0, IDEWorkbenchMessages.GlobalBuildAction_buildProblems,
                         null);
                 monitor.beginTask(getOperationMessage(), 100);
                 try {
                     ResourcesPlugin.getWorkspace().build(buildType,
                             new SubProgressMonitor(monitor, 100));
                 } catch (CoreException e) {
                     status.add(e.getStatus());
                 } finally {
                     monitor.done();
                 }
                 return status;
             }

             /*
              * (non-Javadoc)
              *
              * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
              */
             public boolean belongsTo(Object family) {
                 return ResourcesPlugin.FAMILY_MANUAL_BUILD == family;
             }
         };
         buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory()
                 .buildRule());
         buildJob.setUser(true);
         buildJob.schedule();
     }

     /**
      * Returns an array of all projects in the workspace
      */
     /* package */IProject[] getWorkspaceProjects() {
         return ResourcesPlugin.getWorkspace().getRoot().getProjects();
     }

     /*
      * (non-Javadoc) Method declared on IAction.
      *
      * Builds all projects within the workspace. Saves all editors prior to
      * build depending on user's preference.
      */
     public void run() {
         if (workbenchWindow == null) {
             // action has been disposed
 return;
         }
         // Do nothing if there are no projects...
 IProject[] roots = getWorkspaceProjects();
         if (roots.length < 1) {
             return;
         }
         // Verify that there are builders registered on at
 // least one project
 if (!verifyBuildersAvailable(roots)) {
             return;
         }
         if (!verifyNoManualRunning()) {
             return;
         }
         // Save all resources prior to doing build
 BuildUtilities.saveEditors(null);
         // Perform the build on all the projects
 doBuildOperation();
     }

     /**
      * Checks that there is at least one project with a builder registered on
      * it.
      */
     /* package */boolean verifyBuildersAvailable(IProject[] roots) {
         try {
             for (int i = 0; i < roots.length; i++) {
                 if (roots[i].isAccessible()) {
                     if (roots[i].getDescription().getBuildSpec().length > 0) {
                         return true;
                     }
                 }
             }
         } catch (CoreException e) {
             IDEWorkbenchPlugin.log(getClass(), "verifyBuildersAvailable", e); //$NON-NLS-1$
 ErrorDialog
                     .openError(
                             getShell(),
                             IDEWorkbenchMessages.GlobalBuildAction_buildProblems,
                             NLS.bind(IDEWorkbenchMessages.GlobalBuildAction_internalError, e.getMessage()),
                             e.getStatus());
             return false;
         }
         return false;
     }

     /*
      * (non-Javadoc) Method declared on ActionFactory.IWorkbenchAction.
      *
      * @since 3.0
      */
     public void dispose() {
         if (workbenchWindow == null) {
             // action has already been disposed
 return;
         }
         workbenchWindow = null;
     }

     /**
      * Verify that no manual build is running. If it is then give the use the
      * option to cancel. If they cancel, cancel the jobs and return true,
      * otherwise return false.
      *
      * @return whether or not there is a manual build job running.
      */
     private boolean verifyNoManualRunning() {
         Job[] buildJobs = Platform.getJobManager().find(
                 ResourcesPlugin.FAMILY_MANUAL_BUILD);
         if (buildJobs.length == 0) {
             return true;
         }
         boolean cancel = MessageDialog.openQuestion(workbenchWindow.getShell(),
                 IDEWorkbenchMessages.GlobalBuildAction_BuildRunningTitle,
                 IDEWorkbenchMessages.GlobalBuildAction_BuildRunningMessage);
         if (cancel) {
             for (int i = 0; i < buildJobs.length; i++) {
                 Job job = buildJobs[i];
                 job.cancel();
             }
         }
         //If they cancelled get them to do it again.
 return false;
     }
 }

